package com.york.subject.domain.util;

import com.alibaba.fastjson.JSON;
import com.google.common.cache.Cache;
import com.google.common.cache.CacheBuilder;
import org.apache.commons.lang3.StringUtils;
import org.springframework.stereotype.Component;
import org.springframework.util.CollectionUtils;

import java.util.ArrayList;
import java.util.HashMap;
import java.util.List;
import java.util.Map;
import java.util.concurrent.TimeUnit;
import java.util.function.Function;

/**
 * 缓存工具类
 */
@Component
public class CacheUtil<K, V> {

    private Cache<String, String> localCache =
            CacheBuilder.newBuilder()
                    .maximumSize(5000)
                    .expireAfterWrite(10, TimeUnit.SECONDS)
                    .build();


    /**
     * 非常值得学习的思路
     * 首先它是用本地缓存的，cacheKey就是缓存的key
     * 这里用了泛型K，V（主要是用V，K的话可以用下面的map的逻辑，我们主要学习这个V的逻辑就好）
     * Function<String, List<V>> function就是我们的函数式接口，它的作用就是传入一个String，返回一个List<V>
     * 对于缓存，我们的key是String，但是value类型不一定
     * 所以我们用V这个泛型接受Class对象，使得下面的序列化知道要反序列化成什么类型的对象
     * 至于函数式接口，这个点就是要学习的一部分，我们可以把一个函数作为参数调用进来
     * 这样的话，调用这个方法就可以一行代码搞定
     * 只需要将实现Function的多个方法自由的调用即可
     *
     * @param cacheKey 缓存key
     * @param clazz    从缓存get到的结果反序列化时需要的类型
     * @param function 当缓存中没有数据的时候，需要执行查找的逻辑从而返回结果
     * @return 返回缓存中的结果
     */
    public List<V> getResult(String cacheKey, Class<V> clazz,
                             Function<String, List<V>> function) {
        List<V> resultList = new ArrayList<>();
        String content = localCache.getIfPresent(cacheKey);
        if (StringUtils.isNotBlank(content)) {
            resultList = JSON.parseArray(content, clazz);
        } else {
            resultList = function.apply(cacheKey);
            if (!CollectionUtils.isEmpty(resultList)) {
                localCache.put(cacheKey, JSON.toJSONString(resultList));
            }
        }
        return resultList;
    }

    public Map<K, V> getMapResult(String cacheKey, Class<V> clazz,
                                  Function<String, Map<K, V>> function) {
        return new HashMap<>();
    }

}
